﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Kokomo.Mirror.Ia32
{
	public class Ia32DisassemblyBlock : Ia32DisassemblyBase
	{
		internal Ia32DisassemblyBlock(
			long baseAddress,
			int length,
			IEnumerable<Ia32Instruction> instructions
			)
			:base(baseAddress,length)
		{
			if (instructions == null) throw new ArgumentNullException("instructions");

			this._instructions = instructions;

			Ia32Instruction lastInstruction = instructions.LastOrDefault();
			if (lastInstruction != null)
			{
				FlowControl lastFlowControl = lastInstruction.OpCode.Mnemonic.FlowControl;
				this.HasFallthrough =
					(lastFlowControl == FlowControl.ConditionalJump)
					|| (lastFlowControl == FlowControl.Loop)
					|| (lastFlowControl == FlowControl.Call)
					|| (lastFlowControl== FlowControl.Normal)
					;
				this.HasFinalJump =
					(lastFlowControl == FlowControl.Jump)
					|| (lastFlowControl == FlowControl.ConditionalJump)
					|| (lastFlowControl == FlowControl.Loop)
					;

				JumpTarget lastJumpTarget = lastInstruction.Operands.FirstOrDefault() as JumpTarget;
				if (lastJumpTarget != null)
					this.FinalJumpAddress = lastJumpTarget.TargetOffset;
			}
		}

		public override string ToString()
		{
			return string.Format("{0:X}h - {1:X}h", this.BaseAddress, this.BaseAddress + this.Length - 1);
		}

		public override bool ContainsAddress(long address)
		{
			return
				(address >= this.BaseAddress)
				&& (address < (this.BaseAddress + this.Length))
				;
		}

		private IEnumerable<Ia32Instruction> _instructions;
		public override IEnumerable<Ia32Instruction> Instructions
		{
			get { return this._instructions; }
		}

		public bool HasFinalJump { get; private set; }
		public long FinalJumpAddress { get; private set; }
		public bool HasFallthrough { get; private set; }
	}
}
